<template>
  <CoolDialog v-model="showDialog" width="57vw" @close="close">
    <el-form :model="nodeConfigFrom">
      <div>
        <p>{{ langMsg?.nodename || "节点名称" }}</p>
        <el-input
          v-model="nodeConfigFrom.nodeName"
          @focus="canInput = true"
          @blur="canInput = false"
          placeholder="请输入节点名称"
          maxlength="100"
          show-word-limit
        ></el-input>
      </div>
      <div>
        <p>规则表达式</p>
        <el-input
          id="ruleExp"
          ref="ruleExpRef"
          v-model="ruleExpress"
          type="textarea"
          @focus="setRuleCursor"
          @blur="inputBlur"
          placeholder="规则表达式"
        />
        <p>执行表达式</p>
        <el-input
          id="exeExp"
          ref="exeExpRef"
          v-model="exeExpress"
          type="textarea"
          @focus="setExeCursor"
          @blur="inputBlur"
          placeholder="执行表达式"
        />
      </div>
    </el-form>

    <div>
      <el-row>
        <el-col :span="24" style="padding-right: 10px">
          <div class="div-direct">
            <el-select
              ref="pointsRef"
              placeholder="选测点"
              @change="pointChange"
              class="margin-content"
              value-key="pointTag"
              filterable
              @focus="canInput = true"
              @blur="canInput = false"
            >
              <el-option
                v-for="item in pointList"
                :label="item.pointName"
                :value="item"
                :key="item.pointTag"
              ></el-option>
            </el-select>
            <el-select
              ref="coresRef"
              :disabled="currFocus == 'exeExp'"
              placeholder="选设备类型"
              class="margin-content"
              @change="deviceTypeChange"
              value-key="deviceTypeKey"
              filterable
              @focus="canInput = true"
              @blur="canInput = false"
            >
              <el-option
                v-for="item in deviceTypeList"
                :label="item.deviceTypeName"
                :value="item"
                :key="item.deviceTypeKey"
              ></el-option>
            </el-select>
            <el-select
              ref="trunkRef"
              :disabled="currFocus == 'exeExp'"
              placeholder="选设备"
              class="margin-content"
              @change="deviceChange"
              filterable
              @focus="canInput = true"
              @blur="canInput = false"
              value-key="deviceName"
            >
              <el-option
                v-for="item in deviceList"
                :label="item.name"
                :value="item"
                :key="item.deviceName"
              ></el-option>
            </el-select>
            <el-select
              ref="funcRef"
              placeholder="常用函数"
              @change="funcChange"
              class="margin-content"
            >
              <el-option
                v-for="item in funcList"
                :label="item.description"
                :value="item.operator"
                :key="item.operator"
              ></el-option>
            </el-select>
            <el-button @click="buttonFuc('面积')" v-if="showArea">面积</el-button>
          </div>
          <div class="div-direct">
            <el-button
              v-for="item in deciders"
              @click="buttonFuc(item)"
              :disabled="
                (currFocus == 'exeExp' && item.val != '=') ||
                (currFocus == 'ruleExp' && item.val == '=')
              "
              >{{ item.val }}</el-button
            >
          </div>
          <div class="div-direct buttons-warp">
            <el-button v-for="item in excenumbs" @click="buttonFuc(item)">{{
              item.val || item
            }}</el-button>
          </div>
        </el-col>
      </el-row>
    </div>
    <div style="text-align: center">
      <el-button @click="ok">确定</el-button>
      <el-button @click="close">{{ langMsg?.cancel || "取消" }}</el-button>
    </div>
  </CoolDialog>
</template>
<script lang="ts" setup>
import { LinkedList } from "./util";
import { nodeTypeEnum } from "../const";
import CoolDialog from "@/components/CoolDialog.vue";
import { inject, nextTick, onMounted, onUnmounted, ref } from "vue";
const props = defineProps({
  modelValue: { type: String, default: "0" },
  clickNodeInfo: { type: Object, default: {} },
});
const apis: any = inject("apis");
const langMsg: any = inject("langMsg");
const showArea: any = inject("showArea");
const emits = defineEmits(["update:modelValue", "delete", "saveConfiguration"]);
const ruleExpRef = ref();
const exeExpRef = ref();
//下拉选框ref
const pointsRef = ref();
const coresRef = ref();
const funcRef = ref();
const trunkRef = ref();
//当前获得焦点的输入框
const currFocus = ref();
const deciders = [
  { val: "=" },
  { val: "!=", type: "logic" },
  { val: ">", type: "logic" },
  { val: ">=", type: "logic" },
  { val: "==", type: "logic" },
  { val: "<", type: "logic" },
  { val: "<=", type: "logic" },
  { val: "并且", type: "logic" },
  { val: "或者", type: "logic" },
];
const excenumbs: any = [
  1,
  2,
  3,
  4,
  5,
  6,
  7,
  8,
  9,
  0,
  "(",
  ")",
  "空",
  { val: "+", type: "calc" },
  { val: "-", type: "calc" },
  { val: "*", type: "calc" },
  { val: "/", type: "calc" },
  ".",
  ",",
];

//规则表达式
const ruleExpress = ref("");
let ruleLink = new LinkedList();
let ruleRaw = ruleExpress.value;
//执行表达式
const exeExpress = ref("");
let exeLink = new LinkedList();
let exeRaw = exeExpress.value;
// //输入,附加信息
// interface Field {
//   type: string;
//   field: string;
// }
// const ruleFieldList = ref(<Field[]>[]);
// const addFiled = (obj: Field) => {
//   ruleFieldList.value = ruleFieldList.value.filter(
//     (item) => item.field != obj.field
//   );
//   ruleFieldList.value.push(obj);
// };
//公共方法
const getFocus = (id?: any) => {
  nextTick(() => {
    currFocus.value = id;
    let el: any = document.getElementById(id);
    el && el.focus();
  });
};
//设备
const deviceList = ref();
const getDevices = async () => {
  let res = await apis?.getDeviceList();
  deviceList.value = res.data.data;
};
//设备类型
const deviceTypeList = ref();
const getDeviceType = async () => {
  let res = await apis?.getDeviceTypeList();
  deviceTypeList.value = res.data.data;
};
//函数
const funcList = ref();
const getFuncs = async () => {
  let res = await apis?.getFunctionList();
  funcList.value = res.data.data;
};
const pointList = ref();
const getPoints = async () => {
  let res = await apis?.getExpressPoints();
  pointList.value = res.data.data;
};
const funcChange = (val: any) => {
  //下拉框先失去焦点，输入框才能这只获得焦点，获得焦点的时候会有异步要用nexttick
  funcRef.value.blur();
  insertContentHandle(val, val);
};
const deviceChange = (val: any) => {
  trunkRef.value.blur();
  insertContentHandle(
    "设备=" + val.name,
    '${deviceName}=="' + val.deviceName + '"',
    "DEVICE"
  );
  // addFiled({
  //   field: "deviceName",
  //   type: "BASE",
  // });
};
const deviceTypeChange = (val: any) => {
  coresRef.value.blur();
  insertContentHandle(
    "设备类型=" + val.deviceTypeName,
    '${deviceTypeKey}=="' + val.deviceTypeKey + '"',
    "DEVICETYPE"
  );
  // addFiled({
  //   field: "deviceTypeKey",
  //   type: "BASE",
  // });
};
const pointChange = (val: any) => {
  pointsRef.value.blur();
  insertContentHandle(val.pointName, "${" + val.pointTag + "}", "POINT");
  // addFiled({
  //   field: val.pointTag,
  //   type: "POINT",
  // });
};
enum chartEnum {
  面积 = "${Area}",
  并且 = "&&",
  或者 = "||",
  空 = "null",
}
const buttonFuc = (item: any) => {
  let content = item.val || item;
  let type = item.type || null;
  if (chartEnum[content]) {
    insertContentHandle(content, chartEnum[content], type);
  } else {
    insertContentHandle(content, null, type);
  }
  // if (item == "面积")
  //   addFiled({
  //     field: "面积",
  //     type: "EXTRA",
  //   });
};

//失去焦点，获取焦点位置，为后续在焦点位置添加
const blurIndex = ref();
const inputBlur = (val: any) => {
  //失去焦点，获取焦点位置
  blurIndex.value = val.srcElement.selectionStart;
};
const ruleLastPosition = ref(0);
const setRuleCursor = () => {
  currFocus.value = "ruleExp";
  nextTick(() => {
    ruleExpRef.value.$el.children[0].setSelectionRange(
      ruleLastPosition.value,
      ruleLastPosition.value
    );
  });
};

const setExeCursor = (el: any) => {
  currFocus.value = "exeExp";
  nextTick(() => {
    el.srcElement.setSelectionRange(ruleLastPosition.value, ruleLastPosition.value);
  });
};
// 添加内容的方法
const insertContentHandle = (text: any, engData?: any, textType?: any) => {
  handleSelectionChange();
  ruleLastPosition.value = blurIndex.value;
  let insertSuccess = false;
  let index = blurIndex.value;
  if (currFocus.value == "ruleExp") {
    if (notAllowInsert(ruleExpress.value, index)) {
      insertSuccess = ruleLink.insertAtFocus(index, text, engData, textType);
      ruleExpress.value = ruleLink.toString();
      ruleRaw = ruleExpress.value;
      if (insertSuccess) {
        ruleLastPosition.value = blurIndex.value + text.toString().length + 1;
      }
      nextTick(() => {
        getFocus("ruleExp");
      });
    } else {
      nextTick(() => {
        getFocus("ruleExp");
      });
    }
  } else if (currFocus.value == "exeExp") {
    if (notAllowInsert(exeExpress.value, index)) {
      insertSuccess = exeLink.insertAtFocus(index, text, engData, textType);
      exeExpress.value = exeLink.toString();
      exeRaw = exeExpress.value;
      if (insertSuccess) {
        ruleLastPosition.value = blurIndex.value + text.toString().length + 1;
      }
      nextTick(() => {
        getFocus("exeExp");
      });
    } else {
      //不允许添加，光标在原地
      nextTick(() => {
        getFocus("exeExp");
      });
    }
  }
};
//不允许添加数据的情况
const notAllowInsert = (express: any, index: any) => {
  let str = express;
  //这个位置前面或者后面没有空格，不允许添加
  if (index != 0 && index != str.length && str[index] != " " && str[index - 1] != " ") {
    return false;
  }
  return true;
};
//除了个别键，不接受键盘输入
const canInput = ref(false);
const handkeyCode = (event: any) => {
  if (canInput.value) return;
  handleSelectionChange();
  let codeName = "";
  if (event.code == "Delete") {
    codeName = "delete";
  } else if (event.code == "Backspace") {
    codeName = "backspace";
  }
  if (codeName == "backspace" || codeName == "delete") {
    if (currFocus.value == "ruleExp") {
      const focusPotion = getCursorPotion("ruleExp");
      // console.log('删除前内容：' + ruleLink.toString())
      // console.log('删除前光标位置：' + blurIndex.value)
      let position = ruleLink.removeAtFocus(focusPotion[0], focusPotion[1], codeName);
      let pos: any = ruleLink.toPositionString(position)?.length;
      ruleLastPosition.value = pos;
      blurIndex.value = pos;
      ruleExpress.value = ruleLink.toString();
      ruleRaw = ruleExpress.value;
      // console.log("删除后内容" + ruleExpress.value)
      // console.log('删除后光标应该在的位置：' + pos)

      setTimeout(() => {
        ruleExpRef.value.$el.children[0].setSelectionRange(pos, pos);
      }, 10);
    } else {
      const focusPotion = getCursorPotion("exeExp");
      let position = exeLink.removeAtFocus(focusPotion[0], focusPotion[1], codeName);

      let pos = exeLink.toPositionString(position)?.length;
      ruleLastPosition.value = pos;
      blurIndex.value = pos;
      exeExpress.value = exeLink.toString();
      exeRaw = exeExpress.value;
      setTimeout(() => {
        exeExpRef.value.$el.children[0].setSelectionRange(pos, pos);
      }, 10);
    }
  }
  // 'Space'
  const allowedKeys = [
    "Backspace",
    "Delete",
    "ArrowLeft",
    "ArrowRight",
    "ArrowUp",
    "ArrowDown",
  ];
  if (!allowedKeys.includes(event.code)) {
    console.log(event.code);
    event.preventDefault();
    if (currFocus.value == "ruleExp") {
      ruleExpress.value = ruleRaw;
    } else {
      exeExpress.value = exeRaw;
    }
  }
};
const handleSelectionChange = () => {
  // 在 selectionchange 事件中重新获取光标位置
  if (ruleExpRef.value && exeExpRef.value) {
    //关闭后使之失效
    let startPos;
    if (currFocus.value == "ruleExp") {
      startPos = ruleExpRef.value.$el.children[0].selectionStart;
    } else {
      startPos = exeExpRef.value.$el.children[0].selectionStart;
    }
    blurIndex.value = startPos;
  }
};
interface node {
  id?: string;
  nodeName?: string;
  type?: string;
  ruleExpression?: Array<any>;
}
const nodeConfigFrom: any = ref<node>({ nodeName: "" });
const ok = () => {
  let fieldList = [...exeLink.toRuleField(), ...ruleLink.toRuleField()];
  const map = new Map();
  fieldList = fieldList.filter((v) => !map.has(v.field) && map.set(v.field, v));
  nodeConfigFrom.value.ruleExpression = [
    {
      id: expressId.value,
      conditionExpressionStr: ruleLink.toString(),
      executionExpressionStr: exeLink.toString(),
      conditionExpression: ruleLink.toEngString(),
      executionExpression: exeLink.toEngString(),
      ruleFieldList: fieldList,
    },
  ];
  emits("saveConfiguration", {
    ...nodeConfigFrom.value,
    type: nodeTypeEnum.ruleNode,
    ruleExpression: nodeConfigFrom.value.ruleExpression,
  });
  reset();
};
const showDialog = ref(false);
const reset = () => {
  showDialog.value = false;
  nodeConfigFrom.value = {};
  emits("update:modelValue", 0);
};
const close = () => {
  reset();
  if (!props.clickNodeInfo.id) emits("delete");
};
const getCursorPotion = (id: any) => {
  const el: any = document.getElementById(id);
  let pos = 0,
    posEnd = 0;
  if ("selectionStart" in el) {
    pos = el.selectionStart;
    posEnd = el.selectionEnd;
  } else if ("selection" in document) {
    //ie
    el.focus();
    if (document && document.selection) {
      let sel = document.selection.createRange();
      let selLenth = document?.selection.createRange()?.text?.length;
      sel.moveStart("character", -el.value.length);
      pos = sel.text.length - selLenth;
      posEnd = sel.text.length;
    }
  }
  return [pos, posEnd];
};
onMounted(() => {
  showDialog.value = true;
  initInfo();
  window.addEventListener("keydown", handkeyCode); //开启监听键盘按下事件
});
onUnmounted(() => {
  window.removeEventListener("keydown", handkeyCode);
  close();
});
//初始化
const factId = ref();
const expressId = ref(null);
// const initInfo = async (fact?: any, editObj?: any) => {
const initInfo = async () => {
  factId.value = 160;
  getDevices();
  getDeviceType();
  getFuncs();
  getPoints();
  let data: any = {};
  if (props.clickNodeInfo.id) {
    let res = await apis?.getChainNodeDetail(props.clickNodeInfo.id);
    data = res.data.data || {};
    expressId.value = data.ruleExpression[0].id;
  }
  nodeConfigFrom.value = { ...data };
  if (data.ruleExpression) {
    ruleExpress.value = data.ruleExpression[0].conditionExpressionStr;
    ruleLink.parse(
      data.ruleExpression[0].conditionExpressionStr,
      data.ruleExpression[0].conditionExpression
    );
    exeExpress.value = data.ruleExpression[0].executionExpressionStr;
    exeLink.parse(
      data.ruleExpression[0].executionExpressionStr,
      data.ruleExpression[0].executionExpression
    );
    // ruleFieldList.value = data.ruleExpression[0].ruleFieldList || [];
  }
  showDialog.value = true;
};
onUnmounted(() => {
  reset();
});
</script>
<style lang="scss" scoped>
// @import "@/assets/styles/technology-theme";
@use '@/assets/styles/backstage-management/index.scss';

p {
  height: 30px;
  line-height: 30px;
  display: inline-block;
  width: auto;
  color: rgb(0, 186, 173);
  font-weight: bold;
  font-size: 16px;
}

.div-direct {
  display: flex;
  flex-direction: row;
  margin: 15px 0;
}

.buttons-warp {
  flex-wrap: wrap;
  height: 80px;
}

.margin-content {
  margin-right: 15px;
  // width:300px;
}

.div-vertical {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
}

.control {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;

  .control-button {
    width: 100%;
    display: flex;
    justify-content: center;
    margin: 5px 0;
  }
}
</style>
